package com.manyauthenticationway.server.manyauthenticationway.config.handle

import com.fasterxml.jackson.databind.ObjectMapper
import com.manyauthenticationway.server.manyauthenticationway.config.PasswordEncode
import org.apache.commons.collections.MapUtils
import org.bouncycastle.util.encoders.Base64
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.core.Authentication
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException
import org.springframework.security.oauth2.provider.*
import org.springframework.security.oauth2.provider.token.DefaultTokenServices
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
import org.springframework.stereotype.Component
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import java.io.IOException


@Component("MyAuthenticationSuccessHandler")
class MyAuthenticationSuccessHandler: SavedRequestAwareAuthenticationSuccessHandler(){

    @Autowired
    private lateinit var objectMapper: ObjectMapper
    @Autowired
    private lateinit var clientDetailsService: ClientDetailsService
    @Autowired
    private lateinit var redisTokenStoreHandle: RedisTokenStoreHandle

    @Throws(IOException::class, ServletException::class)
    override fun onAuthenticationSuccess(request: HttpServletRequest, response: HttpServletResponse, authentication: Authentication) {
        val header = request.getHeader("Authorization")
        val name = authentication.getName()
        //        String password = (String) authentication.getCredentials();
        if (header == null || !header.startsWith("Basic ")) {
            throw UnapprovedClientAuthenticationException("请求头中无client信息") as Throwable
        }

        val tokens = extractAndDecodeHeader(header, request)
        val clientId = tokens[0]
        val clientDetails = clientDetailsService!!.loadClientByClientId(clientId)
        //传进来的clientSecret
        val inputClientSecret = tokens[1]
        //内存（数据库）中的密码
        val memoryClientSecret = clientDetails.clientSecret
        println("inputClientSecret:"+inputClientSecret)
        println("clientDetails.clientSecret:"+clientDetails.clientSecret)
        if (clientDetails == null) {
            throw UnapprovedClientAuthenticationException("clientId对应的配置信息不存在:$clientId")
        } else if (!PasswordEncode().matches(inputClientSecret,memoryClientSecret)) {
            throw UnapprovedClientAuthenticationException("clientSecret不匹配:$clientId")
        }

        val tokenRequest = TokenRequest(MapUtils.EMPTY_MAP as MutableMap<String, String>?, clientId, clientDetails.scope, "custom")

        val oAuth2Request = tokenRequest.createOAuth2Request(clientDetails)

        val oAuth2Authentication = OAuth2Authentication(oAuth2Request, authentication)

        val token = defaultTokenServices().createAccessToken(oAuth2Authentication)
        response.contentType = "application/json;charset=UTF-8"
        response.writer.write(objectMapper!!.writeValueAsString(token))
    }

    @Throws(IOException::class)
    private fun extractAndDecodeHeader(header: String, request: HttpServletRequest): Array<String> {

        val base64Token = header.substring(6).toByteArray(charset("UTF-8"))
        val decoded: ByteArray
        try {
            decoded = Base64.decode(base64Token)
        } catch (e: IllegalArgumentException) {
            throw BadCredentialsException("Failed to decode basic authentication token")
        }

        val token = String(decoded)
        val delim = token.indexOf(":")
        if (delim == -1) {
            throw BadCredentialsException("Invalid basic authentication token")
        }
        return arrayOf(token.substring(0, delim), token.substring(delim + 1))
    }
    @Bean
    fun defaultTokenServices(): DefaultTokenServices {
        val tokenServices = DefaultTokenServices()
        tokenServices.setTokenStore(redisTokenStoreHandle.tokenStore())
        tokenServices.setSupportRefreshToken(true)
        tokenServices.setClientDetailsService(clientDetailsService)
        tokenServices.setAccessTokenValiditySeconds(60 * 60 * 12)  // token有效期自定义设置，默认12小时
        tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7)  // refresh_token默认30天
        return tokenServices
    }
}